package cn.minimelon.solon.utils;

import cn.hutool.core.util.StrUtil;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

public class DataSchemeUtils {
    /**
     * 获取数据库中的所有表名
     * @param dataSource 数据源
     * @return 表名列表
     * @throws SQLException 数据库访问异常
     */
    public static List<String> getAllTableNames(DataSource dataSource) throws SQLException {
        List<String> tableNames = new ArrayList<>();

        try (Connection connection = dataSource.getConnection()) {
            DatabaseMetaData metaData = connection.getMetaData();

            // 获取所有表信息
            try (ResultSet tables = metaData.getTables(null, null, "%", new String[]{"TABLE"})) {

                while (tables.next()) {
                    String tableName = tables.getString("TABLE_NAME");
                    tableNames.add(tableName);
                }
            }
        }

        return tableNames;
    }

    /**
     * 获取数据库表的列信息
     */
    private static Map<String, ColumnInfo> getTableColumns(DatabaseMetaData metaData, String tableName) throws SQLException {
        Map<String, ColumnInfo> columns = new HashMap<>();
        try (ResultSet rs = metaData.getColumns(null, null, tableName, null)) {
            while (rs.next()) {
                String columnName = rs.getString("COLUMN_NAME");
                String dataType = rs.getString("TYPE_NAME");
                int columnSize = rs.getInt("COLUMN_SIZE");
                boolean nullable = rs.getInt("NULLABLE") == DatabaseMetaData.columnNullable;
                String defaultValue = rs.getString("COLUMN_DEF");

                columns.put(columnName, new ColumnInfo(columnName, dataType, columnSize, nullable, defaultValue));
            }
        }
        return columns;
    }

    /**
     * 获取数据库表的列信息
     */
    public static Map<String, ColumnInfo> getTableColumns(DataSource dataSource, String tableName) throws SQLException {
        try (Connection conn = dataSource.getConnection()) {
            DatabaseMetaData metaData = conn.getMetaData();
            return getTableColumns(metaData, tableName);
        }
    }

    /**
     * 比较两个表的列差异
     */
    public static void compareTableColumns(String tableName, Map<String, ColumnInfo> db1Columns, Map<String, ColumnInfo> db2Columns) {
        System.out.println("=== 比较表 " + tableName + " 的字段差异 ===");

        // 找出db1有而db2没有的列
        Set<String> db1Only = new HashSet<>(db1Columns.keySet());
        db1Only.removeAll(db2Columns.keySet());

        // 找出db2有而db1没有的列
        Set<String> db2Only = new HashSet<>(db2Columns.keySet());
        db2Only.removeAll(db1Columns.keySet());

        // 找出两个表都有但属性不同的列
        Set<String> common = new HashSet<>(db1Columns.keySet());
        common.retainAll(db2Columns.keySet());

        // 输出结果
        if (!db1Only.isEmpty()) {
            System.out.println("\n数据库1独有的列:");
            for (String col : db1Only) {
                System.out.println("  " + db1Columns.get(col));
            }
        }

        if (!db2Only.isEmpty()) {
            System.out.println("\n数据库2独有的列:");
            for (String col : db2Only) {
                System.out.println("  " + db2Columns.get(col));
            }
        }

        if (!common.isEmpty()) {
            System.out.println("\n两个表共有但属性不同的列:");
            for (String col : common) {
                ColumnInfo col1 = db1Columns.get(col);
                ColumnInfo col2 = db2Columns.get(col);

                if (!col1.equals(col2)) {
                    System.out.println("  列名: " + col);
                    System.out.println("    数据库1: " + col1);
                    System.out.println("    数据库2: " + col2);
                }
            }
        }

        if (db1Only.isEmpty() && db2Only.isEmpty()) {
            System.out.println("\n两个表的字段结构完全相同");
        }
    }

    /**
     * 列信息封装类
     */
    public static class ColumnInfo {
        String name;
        String dataType;
        int size;
        boolean nullable;
        String defaultValue;

        public ColumnInfo(String name, String dataType, int size, boolean nullable, String defaultValue) {
            this.name = name;
            this.dataType = dataType;
            this.size = size;
            this.nullable = nullable;
            this.defaultValue = defaultValue;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (obj == null || getClass() != obj.getClass()) return false;

            ColumnInfo that = (ColumnInfo) obj;
            return size == that.size &&
                    nullable == that.nullable &&
                    StrUtil.equals(name, that.name) &&
                    StrUtil.equals(dataType, that.dataType) &&
                    StrUtil.equals(defaultValue, that.defaultValue);
        }

        @Override
        public String toString() {
            return String.format("%s %s(%d) %s NULL %s",
                    name,
                    dataType,
                    size,
                    nullable ? "ALLOW" : "NOT",
                    defaultValue != null ? "DEFAULT " + defaultValue : "");
        }
    }
}
